let b = {
  a: 11,
};
let test = {
  a: 11,
  bb: "bb",
  ccc: false,
  dd: b,
};

/**
 * 小坑：
 * 1.key和value都占用空间
 * 2.value使用相同引用时只占用一块内存
 */

let set = new WeakSet();

function sizeOf(obj) {
  if (obj === null) {
    return 0;
  }
  let bytes = 0;
  //计算key占用的空间
  const keys = Object.keys(obj);
  for (let i = 0; i < keys.length; i++) {
    let key = keys[i];
    bytes += calculator(key);
    if (typeof obj[key] === "object" && obj[key] !== null) {
      //如果已经计算过该对象则跳过此次循环
      if (set.has(obj[key])) {
        continue;
      }
      set.add(obj[key]);
    }
    bytes += calculator(obj[key]);
  }
  return bytes;
}

function calculator(obj) {
  const type = typeof obj;
  switch (type) {
    case "string":
      return 2 * obj.length;
    case "boolean":
      return 4;
    case "number":
      return 8;
    case "object": {
      if (Array.isArray(obj)) {
        return obj.map(calculator).reduce((res, cur) => {
          return res + cur;
        }, 0);
      } else {
        return sizeOf(obj);
      }
    }
    default:
      return 0;
  }
}

console.log(sizeOf(test));
